package com.sugar.queryinfo.module.business.service.userextend;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.sugar.queryinfo.framework.common.exception.ServiceException;
import com.sugar.queryinfo.module.business.service.userbalancerecord.UserBalanceRecordService;
import com.sugar.queryinfo.module.business.util.ObjLockUtil;
import com.sugar.queryinfo.module.infra.api.file.FileApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

import com.sugar.queryinfo.module.business.controller.admin.userextend.vo.*;
import com.sugar.queryinfo.module.business.dal.dataobject.userextend.UserExtendDO;
import com.sugar.queryinfo.framework.common.pojo.PageResult;

import com.sugar.queryinfo.module.business.dal.mysql.userextend.UserExtendMapper;

import static com.sugar.queryinfo.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.queryinfo.framework.common.util.collection.CollectionUtils.convertList;
import static com.sugar.queryinfo.module.business.enums.ErrorCodeConstants.*;

/**
 * 用户信息拓展 Service 实现类
 *
 * @author Ysugar
 */
@Slf4j
@Service
@Validated
public class UserExtendServiceImpl implements UserExtendService {

    @Resource
    private UserExtendMapper userExtendMapper;
    @Resource
    private UserBalanceRecordService balanceRecordService;

    @Resource
    private FileApi fileApi;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateUserBalance(UserExtendSaveReqVO reqVO) {
        Long userId = reqVO.getUserId();
        BigDecimal amount = reqVO.getAmount();
        // 针对于变动金额过低的，则不进行变动
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("用户 [{}] 变动 {} 金额 低于零，因此未分配！", userId, amount);
            return;
        }

        ReentrantLock lock = ObjLockUtil.obtainLock(ObjLockUtil.generatorKey("USER_BALANCE_{}", userId));
        try {
            lock.lock();
            // 获取用户信息
            UserExtendDO userExtend = getUserExtendByUserId(userId);
            if (Objects.nonNull(userExtend)){
                BigDecimal preBalance = userExtend.getBalance();

                // 若是扣除，则判断余额是否足够
                Boolean type = reqVO.getType();
                if (!type) {
                    // 判断余额是否足够
                    if (preBalance.compareTo(amount) < 0)
                        throw exception(USER_EXTEND_BALANCE_INSUFFICIENT);
                }

                BigDecimal postBalance = type ? preBalance.add(amount) : preBalance.subtract(amount);

                // 更新用户余额
                userExtendMapper.update(UserExtendDO::getUserId, userId, UserExtendDO::getBalance, postBalance);

                // 插入余额变动记录
                balanceRecordService.insertBalanceRecord(reqVO, preBalance, postBalance);
            }
        } catch (ServiceException se) {
            throw se;
        } catch (Throwable e) {
            log.error("用户余额更新失败：", e);
            throw exception(USER_EXTEND_BALANCE_UPDATE_ERROR);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    public void createUserExtend(Long userId) {
        // 生成二维码
        byte[] qrCodeBytes = QrCodeUtil.generatePng("https://zhidunfk.com/business/userauth?id=" + userId + "&time=" + System.currentTimeMillis(),
                200, 200);

        String qrCodeUrl = fileApi.createFile(qrCodeBytes);

        // 插入
        if (userExtendMapper.insert(new UserExtendDO().setUserId(userId).setBalance(BigDecimal.ZERO).setQrCodeUrl(qrCodeUrl)) <= 0)
            throw exception(USER_EXTEND_BALANCE_CREATE_ERROR);
    }

    @Override
    public void deleteUserExtend(Long userId) {
        // 删除
        userExtendMapper.delete(UserExtendDO::getUserId, userId);
    }

    @Override
    public UserExtendDO getUserExtend(Long id) {
        UserExtendDO userExtendDO = userExtendMapper.selectById(id);

        if (Objects.isNull(userExtendDO))
            throw exception(USER_EXTEND_NOT_EXISTS);

        return userExtendDO;
    }

    @Override
    public UserExtendDO getUserExtendByUserId(Long userId) {
        UserExtendDO userExtendDO = userExtendMapper.selectOne(UserExtendDO::getUserId, userId);

        if (Objects.isNull(userExtendDO))
            throw exception(USER_EXTEND_NOT_EXISTS);

        return userExtendDO;
    }

    @Override
    public PageResult<UserExtendRespVO> getUserExtendPage(UserExtendPageReqVO pageReqVO) {
        return userExtendMapper.selectPage(pageReqVO);
    }

    @Override
    public BigDecimal refreshUserBalance(Long userId) {
        UserExtendDO userExtendDO = userExtendMapper.selectOne(UserExtendDO::getUserId, userId);
        if (Objects.isNull(userExtendDO))
            return BigDecimal.ZERO;
        return userExtendDO.getBalance();
    }

    @Override
    public String getUserQrCode(Long userId) {
        UserExtendDO userExtendDO = userExtendMapper.selectOne(UserExtendDO::getUserId, userId);
        if (Objects.isNull(userExtendDO))
            return null;
        String qrCodeUrl = userExtendDO.getQrCodeUrl();
        if (StrUtil.isBlank(qrCodeUrl)){
            // 生成二维码
            byte[] qrCodeBytes = QrCodeUtil.generatePng("https://zhidunfk.com/business/userauth?id=" + userId + "&time=" + System.currentTimeMillis(),
                    400, 400);

            qrCodeUrl = fileApi.createFile(qrCodeBytes);
            // 更新
            userExtendMapper.update(UserExtendDO::getUserId, userId, UserExtendDO::getQrCodeUrl, qrCodeUrl);
        }
        return qrCodeUrl;
    }

    @Override
    public String refreshUserQrCode(Long userId) {
        UserExtendDO userExtendDO = userExtendMapper.selectOne(UserExtendDO::getUserId, userId);
        if (Objects.isNull(userExtendDO))
            return null;

        // 生成二维码
        byte[] qrCodeBytes = QrCodeUtil.generatePng("https://zhidunfk.com/business/userauth?id=" + userId + "&time=" + System.currentTimeMillis(),
                200, 200);

        String qrCodeUrl = fileApi.createFile(qrCodeBytes);
        // 更新
        userExtendMapper.update(UserExtendDO::getUserId, userId, UserExtendDO::getQrCodeUrl, qrCodeUrl);

        return qrCodeUrl;
    }
}